package spring.security.core.mobile.filter;

import java.io.IOException;
import java.util.HashSet;
import java.util.Set;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.social.connect.web.HttpSessionSessionStrategy;
import org.springframework.social.connect.web.SessionStrategy;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.bind.ServletRequestUtils;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.filter.OncePerRequestFilter;

import spring.security.core.properties.SecurityProperties;
import spring.security.core.validatecode.ValidateCodeCode;
import spring.security.core.validatecode.ValidateCodeController;
import spring.security.core.validatecode.ValidateCodeException;

public class SmsCodeFilter extends OncePerRequestFilter implements InitializingBean {

	private AuthenticationFailureHandler authenticationFailureHandler;

	private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy();

	private Set<String> urls = new HashSet<>();

	private SecurityProperties securityProperties;

	private AntPathMatcher pathMatcher = new AntPathMatcher();
	
	private static String session_key = ValidateCodeController.SESSION_KEY + "SMS";

	@Override
	public void afterPropertiesSet() throws ServletException {
		super.afterPropertiesSet();
		String[] strings = StringUtils
				.splitByWholeSeparatorPreserveAllTokens(securityProperties.getCode().getSms().getUrls(), ",");
		if(ArrayUtils.isNotEmpty(strings)) {
			for (String string : strings) {
				urls.add(string);
			}
		}
		urls.add("/auth/mobile");
	}

	@Override
	protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
			throws ServletException, IOException {
		boolean action = false;
		for (String string : urls) {
			boolean match = pathMatcher.match(string, request.getRequestURI());
			if (match) {
				action = true;
			}
		}
		if (action) {
			try {
				validate(new ServletWebRequest(request));
			} catch (ValidateCodeException e) {
				authenticationFailureHandler.onAuthenticationFailure(request, response, e);
				return;
			}
		}

		filterChain.doFilter(request, response);

	}

	private void validate(ServletWebRequest request) throws ServletRequestBindingException {
		ValidateCodeCode imageCode = (ValidateCodeCode) sessionStrategy.getAttribute(request, session_key);

		String code = ServletRequestUtils.getStringParameter(request.getRequest(), "smsCode");
		if (StringUtils.isBlank(code)) {
			throw new ValidateCodeException("验证码信息为空!");
		} else if (imageCode == null) {
			throw new ValidateCodeException("验证码不存在!");
		} else if (imageCode.isExpried()) {
			sessionStrategy.removeAttribute(request, session_key);
			throw new ValidateCodeException("验证码已过期!");
		} else if (!StringUtils.equals(imageCode.getCode(), code)) {
			throw new ValidateCodeException("验证码不匹配!");
		}

		sessionStrategy.removeAttribute(request, session_key);
	}

	public AuthenticationFailureHandler getAuthenticationFailureHandler() {
		return authenticationFailureHandler;
	}

	public void setAuthenticationFailureHandler(AuthenticationFailureHandler authenticationFailureHandler) {
		this.authenticationFailureHandler = authenticationFailureHandler;
	}

	public Set<String> getUrls() {
		return urls;
	}

	public void setUrls(Set<String> urls) {
		this.urls = urls;
	}

	public SecurityProperties getSecurityProperties() {
		return securityProperties;
	}

	public void setSecurityProperties(SecurityProperties securityProperties) {
		this.securityProperties = securityProperties;
	}
}
